package kin.serviceIMP.system;

import java.io.Serializable;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Service;

import kin.bean.system.Form;
import kin.bean.system.Result;
import kin.dao.system.FormManagerIMP;

import kin.system.util.StringUtil;

@Service
public class BaseServiceManagerIMP<T> implements ApplicationContextAware
// ,BeanFactoryAware

{

	protected Class<T> entityClass;
	private ApplicationContext applicationContext = null;
	private Object object;

	public BaseServiceManagerIMP() {

		entityClass = getSuperClassGenricType(this.getClass());

	}

	public Object getObject() {
		String name = this.entityClass.getSimpleName();
		this.object = this.applicationContext.getBean(StringUtil
				.fristLetterLowerCase(name) + "ManagerIMP");
		return this.object;
	}

	/*
	 * public void setObject() { String name = this.entityClass.getSimpleName();
	 * this
	 * .object=this.applicationContext.getBean(StringUtil.fristLetterLowerCase
	 * (name)+ "ManagerIMP"); }
	 */

	public Class getSuperClassGenricType(Class clazz) {
		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (!(params[0] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[0];
	}

	public T find(LinkedHashMap<String, Object> where,
			LinkedHashMap<String, Boolean> orderby, String className)
			throws Exception {
		return (T) this.getObject("find", where, orderby, className);
	}

	public List<T> findAll() {

		return (List<T>) this.getObject("findAll");
	}

	public List<T> findList(LinkedHashMap<String, Object> where,
			LinkedHashMap<String, Collection> in,
			LinkedHashMap<String, Boolean> orderby,
			LinkedHashMap<String, Collection> like) throws Exception {
		/*
		 * StandardEvaluationContext context = new StandardEvaluationContext(
		 * this.object); ExpressionParser parser = new SpelExpressionParser();
		 * 
		 * return (List<T>) parser.parseExpression( "findList(" + where + "," +
		 * in + "," + orderby + "," + like + ")").getValue(context);
		 */
		return (List<T>) this.getObject("findList", where, in, orderby, like);
	}

	public Result findPaging(LinkedHashMap<String, Object> where,
			LinkedHashMap<String, String[]> in,
			LinkedHashMap<String, Boolean> orderby, int page, int start, int max)
			throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	public void add(T entity) throws Exception {

		this.getObject("add", entity);
	}

	public SessionFactory getSessionFactory() {
		return (SessionFactory) this.getObject("getSessionFactory");
	}

	public void update(Object entity) throws Exception {

		this.getObject("update", entity);

	}

	public void delete(Serializable entityids) throws Exception {
		this.getObject("delete", entityids);

	}

	public T get(Serializable entityId) {

		return (T) this.getObject("get", entityId);
	}

	public T load(Serializable entityId) {

		return (T) this.getObject("load", entityId);
	}

	private static <P> String getRealName(Class<P> entityClass2) {
		String RealName = entityClass2.getSimpleName();
		return RealName;
	}

	protected Object getObject(String methodName, Object... args) {
		this.getObject();
		Class<?>[] cls = new Class[args.length];
		Object obj = null;
		Method m = null;
		boolean exec = false;

		if (null != args && args.length > 0) {
			cls = new Class[args.length];
			for (int i = 0; i < args.length; i++) {
				if (args[i] != null) {
					cls[i] = args[i].getClass();
				} else {
					cls[i] = null;
				}
			}
		}

		try {

			for (Method method : this.object.getClass().getMethods()) {

				Class<?>[] cl = method.getParameterTypes();

				if (method.getName().equals(methodName)&& (cl.length == cls.length)) {
					
					if (cl.length > 0) {
						for (int j = 0; j < cl.length; j++) {
							Class<?> ca = getClass(method.getGenericParameterTypes()[j], 0);
							if (ca == Object.class) {
								cls[j] = ca;
								exec = true;
							} else {
								// 20140531
								if (cls[j]!=null&&cl[j].isAssignableFrom(cls[j])) {
									// if(cls[j].isAssignableFrom(cl[j])){
									cls[j] = cl[j];
									exec = true;
								} else {
									if(cls[j]==null){
										cls[j]=cl[j];
										exec = true;	
									}else{
									exec = false;
									break;
									}
								}
							}
						}
					} else {
						cls=null;
						exec = true;
					}

				}
			}
			if (exec) {
				m = this.object.getClass().getMethod(methodName, cls);
				obj = m.invoke(this.object, args);
			}

		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return obj;

		// return parser.parseExpression(param).getValue(context);
	}

	public List exportExcel(String query) {
		return null;

	}

	public void deleteAll() {
		/*
		 * FormManagerIMP ff= (FormManagerIMP)
		 * this.applicationContext.getBean("formManagerIMP"); ff.deleteAll();
		 */
		this.getObject("deleteAll");
	}

	private static Class getClass(Type type, int i) {
		if (type instanceof ParameterizedType) { // 处理泛型类型
			return getGenericClass((ParameterizedType) type, i);
		} else if (type instanceof TypeVariable) {
			return (Class) getClass(((TypeVariable) type).getBounds()[0], 0); // 处理泛型擦拭对象
		} else {// class本身也是type，强制转型
			return (Class) type;
		}
	}

	private static Class getGenericClass(ParameterizedType parameterizedType,
			int i) {
		Object genericClass = parameterizedType.getActualTypeArguments()[i];
		if (genericClass instanceof ParameterizedType) { // 处理多级泛型
			return (Class) ((ParameterizedType) genericClass).getRawType();
		} else if (genericClass instanceof GenericArrayType) { // 处理数组泛型
			return (Class) ((GenericArrayType) genericClass)
					.getGenericComponentType();
		} else if (genericClass instanceof TypeVariable) { // 处理泛型擦拭对象
			return (Class) getClass(
					((TypeVariable) genericClass).getBounds()[0], 0);
		} else {
			return (Class) genericClass;
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext arg0)
			throws BeansException {
		this.applicationContext = arg0;

	}

	/*
	 * @Override public void setBeanFactory(BeanFactory arg0) throws
	 * BeansException { // TODO Auto-generated method stub
	 * 
	 * }
	 */

}
